//! unmp-id

#![no_std]
extern crate alloc;

mod blockchain;
mod private;
mod random;
mod special;
mod unique;

pub use blockchain::BlockchainId;
use core::fmt;
pub use private::PrivateId;
pub use random::RandomId;
pub use special::SpecialId;
pub use unique::UniqueId;
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

/// 上级父设备地址
pub const ID_PARENT: Id = SpecialId::new([0x00, 0x00]).id();
/// 下级子设备地址
pub const ID_ALL: Id = SpecialId::new([0xFF, 0xFF]).id();
/// 地址最大长度
pub(crate) const ID_LEN: usize = 33;

/// unmp设备地址类型
#[cfg_attr(feature = "wasm", wasm_bindgen)]
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum IdKind {
    Private = 0x00,
    Random = 0x40,
    Special = 0x60,
    Unique = 0x80,
    Blockchain = 0xA0,
    Unknow,
}
/// unmp设备地址
#[cfg_attr(feature = "wasm", wasm_bindgen)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct Id {
    len: usize,
    buf: [u8; ID_LEN],
}
impl Id {
    /// 无效ID
    pub const INVALID: Id = Id {
        len: 0,
        buf: [0; ID_LEN],
    };
    /// 生成ID
    pub const fn new(id: &[u8]) -> Id {
        let mut buf: [u8; ID_LEN] = [0; ID_LEN];
        let len = id.len();
        let mut i = 0;
        while i < len {
            buf[i] = id[i];
            i += 1;
        }
        Id { len, buf }
    }
    /// 从buf头部分割出Id并返回剩余buf
    pub fn split_buf(buf: &[u8]) -> (Id, &[u8]) {
        let (id, rest) = buf.split_at(((buf[0] & 0x1F) + 2) as usize);
        let id = id.into();
        return (id, rest);
    }
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl Id {
    pub fn kind(&self) -> IdKind {
        if self.len as u8 != ((self.buf[0] & 0x1F) + 2) {
            return IdKind::Unknow;
        }
        match self.buf[0] & 0xE0 {
            x if x == IdKind::Unique as u8 => IdKind::Unique,
            x if x == IdKind::Private as u8 => IdKind::Private,
            x if x == IdKind::Random as u8 => IdKind::Random,
            x if x == IdKind::Blockchain as u8 => IdKind::Blockchain,
            x if x == IdKind::Special as u8 => IdKind::Special,
            _ => IdKind::Unknow,
        }
    }
}
impl fmt::Debug for Id {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Id{:?}({:02X?})", self.kind(), &self.buf[..self.len])
    }
}
impl From<&[u8]> for Id {
    fn from(id: &[u8]) -> Self {
        Id::new(id)
    }
}
impl core::ops::Deref for Id {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        &self.buf[..self.len]
    }
}
impl AsRef<[u8]> for Id {
    fn as_ref(&self) -> &[u8] {
        &self.buf[..self.len]
    }
}
